#include "log.h"
#include <iostream>
#include <time.h>
#include <iomanip>

namespace learnco {

const char* LogLevel::ToString(LogLevel::Level level) {
    switch(level) {
#define XX(name) \
    case LogLevel::name: \
        return #name; \
        break;
    XX(DEBUG);
    XX(INFO);
    XX(WARN);
    XX(ERROR);
    XX(FATAL);
#undef XX
    default:
        return "UNKNOW";
    }
    return "UNKNOW";
}

//当前日志事件(状态保存快照) event
LogEvent::LogEvent(std::shared_ptr<Logger> logger, LogLevel::Level level
            ,std::string file, int32_t line, uint32_t elapse
            ,uint32_t thread_id, uint32_t fiber_id, uint64_t time
            ,const std::string& thread_name)
    :m_logger(logger)
    ,m_level(level)
    ,m_file(file)
    ,m_line(line)
    ,m_elapse(elapse)
    ,m_threadId(thread_id)
    ,m_fiberId(fiber_id)
    ,m_time(time)
    ,m_threadName(thread_name) {
}

//LogFormatter 输出器
std::string LogFormatter::format(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event){
    std::stringstream ss;
    {
        //时间 %Y-%m-%d %H:%M:%S
        struct tm tm;
        time_t time = event->getTime();
        localtime_r(&time, &tm);
        char buf[64];
        strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
        ss << buf << "\t";
    }

    {   
        //Logger名称
        ss << "[" << std::left << std::setw(10) << event->getLogger()->getName() << "]";
        //Level 级别
        ss << "[" << std::left << std::setw(5) << LogLevel::ToString(level) << "]" << "\t";
        //文件名 行数
        ss << "[" << std::left << std::setw(20) << event->getFile()  << "]" << "["<< std::left << std::setw(4) << event->getLine() << "]" << "\t";;
        //线程名称 线程ID
        ss << "[" << std::left << std::setw(15)  << event->getThreadName() << "]" << "["<< std::left << std::setw(4) <<  event->getThreadId() << "]" << "\t";;
        //协程id
        ss << "fiberID" << "--" << event->getFiberId() << "\t";;
        //输入内容
        ss << event->getContent();;
    }



    ss << std::endl;
    return ss.str();
}

//日志器::初始化
Logger::Logger(const std::string& name)
    :m_name(name)
    ,m_level(LogLevel::DEBUG){

}

//日志器::添加输出器
void Logger::addAppender(LogAppender::ptr appender){
    m_appenders.push_back(appender);
}

//日志器::删除输出器
void Logger::delAppender(LogAppender::ptr appender){
    for(auto it = m_appenders.begin(); it != m_appenders.end(); ++it){
        if(*it == appender){
            m_appenders.erase(it);
            break;
        }
    }
}

//日志器::清空输出器
void Logger::clearAppenders() {
    m_appenders.clear(); 
}

//日志器::输出日志
void Logger::log(LogLevel::Level level, LogEvent::ptr event){
    if(level >= m_level){
        auto self = shared_from_this();
        for(auto &i : m_appenders){
            i->log(self, level, event);
        }
    }
}

//文件输出器::构造
FileLogAppender::FileLogAppender(const std::string& filename)
    :m_filename(filename) {
    reopen();
}

//文件输出器::打开文件流
bool FileLogAppender::reopen() {
    if(m_filestream) {
        m_filestream.close();
    }
    //std::ios::app 如果没有文件，生成空文件；如果有文件，在文件尾追加
    m_filestream.open(m_filename, std::ios::app);
    return !!m_filestream;
}


void FileLogAppender::log(Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) {
    if(level >= m_level) {
        uint64_t now = time(0);
        if(now != m_lastTime) {
            reopen();
            m_lastTime = now;
        }
        if(!(m_filestream << LogFormatter::format(logger, level, event))) {
            std::cout << "error" << std::endl;
        }
    }
}


//窗口::日志输出
void StdoutLogAppender::log(Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event){
    if(level >= m_level){
        std::cout << LogFormatter::format(logger, level, event);
    }
}

//单例日志管理器
LoggerManager::LoggerManager() {
    m_root.reset(new Logger);
    m_root->addAppender(LogAppender::ptr(new StdoutLogAppender));

    m_loggers[m_root->m_name] = m_root;
}

Logger::ptr LoggerManager::getLogger(const std::string& name) {
    auto it = m_loggers.find(name);
    if(it != m_loggers.end()) {
        return it->second;
    }

    Logger::ptr logger(new Logger(name));
    logger->addAppender(LogAppender::ptr(new StdoutLogAppender));
    logger->m_root = m_root;
    m_loggers[name] = logger;
    return logger;
}

//事件包装器
LogEventWrap::LogEventWrap(LogEvent::ptr e)
    :m_event(e) {
}

LogEventWrap::~LogEventWrap() {
    m_event->getLogger()->log(m_event->getLevel(), m_event);
}

std::stringstream& LogEventWrap::getSS() {
    return m_event->getSS();
}

}